/**
 * Created by hanj on 2019/11/6 10:34
 */
package geektime.demo;


import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


//JDK8新特性: Stream流对集合的处理
public class CollectionTest {

    public static void main(String[] args) {
        List<Book> books = Arrays.asList(
                new Book("Java编程思想", "机械工业出版社", 108.00D),
                new Book("Java基础", "机械工业出版社", 118.00D),
                new Book("Java 8实战", "人民邮电出版社", 79.00D),
                new Book("MongoDB权威指南（第2版）", "人民邮电出版社", 69.00D)
        );

        //1.过滤和排序
        filterAndSorted();
        //2.查找和匹配
        findAndMatch();
        //3.归纳
        reduceAndMap(books);
        //4.归纳和汇总
        summaryStatistics(books);
        //5.分组
        groupBy(books);
    }

    /**
     * 过滤排序
     */
    private static void filterAndSorted() {
        System.out.println("过滤和排序============");
        Stream.of(1, 8, 5, 2, 1, 0, 9, 2, 0, 4, 8)
                .filter(n -> n > 2)     // 对元素过滤，保留大于2的元素
                .distinct()             // 去重，类似于SQL语句中的DISTINCT
                .skip(1)                // 跳过前面1个元素
                .sorted()               // 对结果排序
                .limit(2)               // 返回开头2个元素，类似于SQL语句中的SELECT TOP
                .forEach(System.out::println);
    }

    /**
     * 查找和匹配
     */
    private static void findAndMatch() {

        System.out.println("查找和匹配===========");
        // 检查流中的任意元素是否包含字符串"Java"
        boolean hasMatch = Stream.of("Java", "C#", "PHP", "C++", "Python")
                .anyMatch(s -> s.equals("Java"));
        System.out.println("检查流中的任意元素是否包含字符串Java:" + hasMatch);

        // 检查流中的所有元素是否都包含字符串"#"
        boolean hasAllMatch = Stream.of("Java", "C#", "PHP", "C++", "Python")
                .allMatch(s -> s.contains("#"));
        System.out.println("检查流中的所有元素是否都包含字符串#:" + hasAllMatch);

        // 检查流中的任意元素是否没有以"C"开头的字符串
        boolean hasNoneMatch = Stream.of("Java", "C#", "PHP", "C++", "Python")
                .noneMatch(s -> s.startsWith("C"));
        System.out.println("检查流中的任意元素是否没有以C开头的字符串:" + hasNoneMatch);

        // 查找元素:findAny和findFirst一样..只返回第一个元素
        Optional<String> hasFindAny = Stream.of("Java", "C++", "PHP", "C#", "Python")
                .filter(s -> s.contains("P"))
                .findAny();
        System.out.println("查找元素:" + hasFindAny);
    }

    /**
     * 归约
     */
    private static void reduceAndMap(List<Book> books) {
        System.out.println("归约=============");

        // 计算所有图书的总价
        Optional<Double> totalPrice = books.stream().map(Book::getPrice).reduce((n, m) -> n + m);
        System.out.println("计算所有图书的总价" + totalPrice);

        // 价格最高的图书
        Optional<Book> max = books.stream().max(Comparator.comparing(Book::getPrice));
        System.out.println("价格最高的图书:" + max);

        //价格最低的图书
        Optional<Book> min = books.stream().min(Comparator.comparing(Book::getPrice));
        System.out.println("价格最低的图书" + min);

        //计算总数
        long count = books.stream().count();
        System.out.println("计算总数" + count);

        //map和flatMap 流的区别
        List<String[]> map = Stream.of("Hello stream").map(s -> s.split("")).collect(Collectors.toList());
        System.out.println("map流:" + map);

        List<String> flatMap = Stream.of("Hello stream").map(s -> s.split(""))
                .flatMap(Arrays::stream).collect(Collectors.toList());
        System.out.println("flatMap流:" + flatMap);
    }

    /**
     * 归纳和汇总
     */
    private static void summaryStatistics(List<Book> books) {
        System.out.println("归纳和汇总==============");

        DoubleSummaryStatistics dss = books.stream().collect(Collectors.summarizingDouble(Book::getPrice));
        double average = dss.getAverage();//平均数
        long count = dss.getCount();//总数
        double sum = dss.getSum();//汇总
        double max = dss.getMax();//最大值
        double min = dss.getMin();//最小值
        System.out.println("平均数:" + average);
        System.out.println("计算总数:" + count);
        System.out.println("汇总:" + sum);
        System.out.println("最大值:" + max);
        System.out.println("最小值:" + min);

        //Collectors类还包含一个joining()方法，该方法用于连接字符串：
        String str = Stream.of("A", "B", "C", "D").collect(Collectors.joining(""));
        System.out.println("joining()方法连接字符串:" + str);

    }

    /**
     * 分组
     *
     * @param books
     */
    private static void groupBy(List<Book> books) {
        System.out.println("分组==============");
        //按照出版社对图书进行分组
        Map<String, List<Book>> list = books.stream().collect(Collectors.groupingBy(Book::getPublisher));
        System.out.println("按照出版社对图书进行分组:" + list);

        //将价格在0-50之间的书籍分成一组，50-100之间的分成一组，超过100的分成一组
        Map<String, List<Book>> listMap = books.stream().collect(Collectors.groupingBy(book -> {
            if (book.getPrice() >= 0 && book.getPrice() <= 50)
                return "A";
            else if (book.getPrice() > 50 && book.getPrice() < 100)
                return "B";
            else
                return "C";
        }));
        System.out.println("将价格在0-50之间的书籍分成一组，50-100之间的分成一组，超过100的分成一组:");
        System.out.println(listMap);

        //先根据出版社分组.再算出每个分组的总数
        Map<String, Long> collect = books.stream().collect(Collectors.groupingBy(Book::getPublisher, Collectors.counting()));
        System.out.println("先根据出版社分组.再算出每个分组的总数:" + collect);

        //在进行分组后获取每组中价格最高的图书
        Map<String, Object> map = books.stream().collect(Collectors.groupingBy(Book::getPublisher, Collectors.collectingAndThen(
                Collectors.maxBy(Comparator.comparingDouble(Book::getPrice)), Optional::get
        )));
        System.out.println("在进行分组后获取每组中价格最高的图书:" + map);
    }

}
